<!-- Copyright 2012 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -->
<!DOCTYPE html>
<title>Unit Test of e2e.openpgp.S2k</title>
<script src="../../../../../javascript/closure/base.js"></script>
<script src="test_js_deps-runfiles.js"></script>
<script src="s2k.js"></script>
<script>
  goog.require('e2e.openpgp.S2k');
  goog.require('e2e.hash.Sha1');
  goog.require('e2e.hash.Sha256');
  goog.require('goog.array');
  goog.require('goog.testing.jsunit');
</script>
<script>
  function testS2KTypeConsume() {
    assertNotThrows('Simple S2K is parsed correctly.', function() {
      var simple = [0x00, 0x02, 0xFF, 0xBB];
      var simples2k = e2e.openpgp.S2k.parse(simple);
      assertArrayEquals(
          'Simple only consumed two bytes.', [0xFF, 0xBB], simple);
      assert('Simple is instance of SimpleS2K',
             simples2k instanceof e2e.openpgp.SimpleS2K);
    });
    assertNotThrows('E2E Dummy S2k is parsed correctly.', function() {
      var dummy = [0x65 /* type value for dummy */, 0x02 /* ID */,
        0x45 /* 'E' */, 0x32 /* '2' */, 0x45 /* E */, 0x1 /* test location */,
        0xFF, 0xBB];
      var dummys2k = e2e.openpgp.S2k.parse(dummy);
      assertArrayEquals('Dummy only consumed 5 bytes', [0xFF, 0xBB], dummy);
      assert('Dummy is instance of DummyS2k',
        dummys2k instanceof e2e.openpgp.DummyS2k);
    });
    assertNotThrows('Salted S2K is parsed correctly.', function() {
      var salted = [0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0xFF, 0xBB];
      var salteds2k = e2e.openpgp.S2k.parse(salted);
      assertArrayEquals(
          'Salted only consumed ten bytes.', [0xFF, 0xBB], salted);
      assert('Salted S2K is instance of SaltedS2K',
             salteds2k instanceof e2e.openpgp.SaltedS2K);
    });
    assertNotThrows('Iterated S2K is parsed correctly.', function() {
      var iterated = [0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x01, 0xFF, 0xBB];
      var iterateds2k = e2e.openpgp.S2k.parse(iterated);
      assertArrayEquals('Iterated only consumed eleven bytes.', [0xFF, 0xBB],
          iterated);
      assert('Iterated S2K is instance of IteratedS2K',
             iterateds2k instanceof e2e.openpgp.IteratedS2K);
    });
  }

  function testS2KDummySmartCardStubMode() {
    assertNotThrows('E2E Dummy S2k is parsed correctly.', function() {
      var dummy = [0x65 /* type value for dummy */, 0x00 /* empty hash algo*/,
        0x47 /* 'G' */, 0x4e /* 'N' */, 0x55 /* U */, 0x2 /* smartcard */,
        0xFF, 0xBB];
      var dummys2k = e2e.openpgp.S2k.parse(dummy);
      assertArrayEquals('Dummy only consumed 5 bytes', [0xFF, 0xBB], dummy);
      assert('Dummy is instance of DummyS2k',
        dummys2k instanceof e2e.openpgp.DummyS2k);
        assert
      assertArrayEquals([0x65, 0x00, 0x47, 0x4e, 0x55, 0x02],
          dummys2k.serialize());
    });
  }


  function testS2KInvalid() {
    assertThrows('Invalid S2K type throws errors', function() {
      var invalid = [0x05, 0x02, 0xFF, 0xBB];
      var simples2k = e2e.openpgp.S2k.parse(invalid);
    });
    assertThrows('Wrong salt length throws errors', function() {
      var invalid = [0x01, 0x02, 0x01];
      var simples2k = e2e.openpgp.S2k.parse(invalid);
    });
    assertThrows('Bad E2E dummy header throws error', function() {
      var invalid = [0x65, 0x02, 0x45 /* E */, 0x33 /* 3 */, 0x45 /* E */, 0x1];
      var dummys2k = e2e.openpgp.S2k.parse(invalid);
    });
  }


  // Test values from https://code.google.com/p/go/source/browse/openpgp/s2k/s2k_test.go?repo=crypto
  function testSalted() {
    var expected = [  // passphrase, hashFunction, salt, expectedKey
      ["hello", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "f4f7d67e"],
      ["world", new e2e.hash.Sha256, [1, 2, 3, 4, 5, 6, 7, 8], "d139e512"],
      ["foo", new e2e.hash.Sha1, [0x00, 0xff, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0x00], "21d985b9"],
      ["bar", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8],
       "06a55f98905d7f533c3b38de977740029111d52f624b696f854333cf46"],
      ["x", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "96307961"],
      ["xxxxxxxxxxxxxxxxxxxxxxx", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "dc357273"],
    ];
    goog.array.forEach(expected, function(row) {
      var s = new e2e.openpgp.SaltedS2K(row[1], row[2]);
      var expectedKey = goog.crypt.hexToByteArray(row[3]);
      var key = s.getKey(goog.crypt.stringToByteArray(row[0]),
                         expectedKey.length);
      assertArrayEquals(expectedKey, key);
    });
  }
  function testIterated() {
    var expected = [  // passphrase, hashFunction, salt, expectedKey
      ["hello", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "e10a93e4"],
      ["world", new e2e.hash.Sha256, [1, 2, 3, 4, 5, 6, 7, 8], "53989b95"],
      ["foo", new e2e.hash.Sha1, [0x00, 0xff, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0x00], "c3dc5ada"],
      ["bar", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8],
       "225fcfeb478ee1d3beeb50e7215ae5d4941033358f7ad7aa1db81d74c1"],
      ["x", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "0597ff19"],
      ["xxxxxxxxxxxxxxxxxxxxxxx", new e2e.hash.Sha1, [1, 2, 3, 4, 5, 6, 7, 8], "8cabcc9b"],
    ];
    goog.array.forEach(expected, function(row) {
      var s = new e2e.openpgp.IteratedS2K(row[1], row[2], 1);  // Count of 1 decoded is 1088.
      var expectedKey = goog.crypt.hexToByteArray(row[3])
      var key = s.getKey(goog.crypt.stringToByteArray(row[0]),
                         expectedKey.length);
      assertArrayEquals(expectedKey, key);
    });
  }
  function testGetCount() {
    assertEquals(e2e.openpgp.IteratedS2K.getCount_(96), 65536);
  }
  function testParse() {
    var expected = [  // Values: packet bytes, passphrase, expected key
      /* Simple with SHA1 */
      ["0002", "hello", "aaf4c61d"],
      /* Salted with SHA1 */
      ["01020102030405060708", "hello", "f4f7d67e"],
      /* Iterated with SHA1. 35651584 (f1 encoded) iterations, which is quite expensive. */
      ["03020102030405060708f1", "hello", "f2a57b7c"],
    ];
    goog.array.forEach(expected, function(row) {
      var packet = goog.crypt.hexToByteArray(row[0]);
      var passphrase = goog.crypt.stringToByteArray(row[1]);
      var expected = goog.crypt.hexToByteArray(row[2]);
      var s2k = e2e.openpgp.S2k.parse(packet);
      assertArrayEquals(expected, s2k.getKey(passphrase, expected.length));
    });
  }
  function testSerialize() {
    var specifications = [
      new e2e.openpgp.SimpleS2K(new e2e.hash.Sha1),
      new e2e.openpgp.SaltedS2K(new e2e.hash.Sha1,
                                    [1, 2, 3, 4, 5, 6, 7, 8]),
      new e2e.openpgp.IteratedS2K(new e2e.hash.Sha1,
                                      [1, 2, 3, 4, 5, 6, 7, 8],
                                      96),
    ];
    goog.array.forEach(specifications, function(specification) {
      var expectedKey = specification.getKey(
          goog.crypt.stringToByteArray("passphrase"), 16);
      var serialized = specification.serialize();
      var parsed = e2e.openpgp.S2k.parse(serialized);
      assertArrayEquals(expectedKey,
                        parsed.getKey(
                            goog.crypt.stringToByteArray("passphrase"), 16));
    });
  }
</script>
